/*
 * Copyright (C) 2006 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.catonine.desktop;

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.Set;

import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;

import nu.zoom.catonine.desktop.impl.FileOpenerImpl;
import nu.zoom.catonine.desktop.rule.StyleRulesPlugIn;
import nu.zoom.catonine.fontchooser.FontChooserFactory;
import nu.zoom.catonine.prefs.Preferences;
import nu.zoom.catonine.swing.memstat.MemStatComponent;
import nu.zoom.gal.error.ErrorReporter;
import nu.zoom.gal.progress.Progress;
import nu.zoom.swing.desktop.PlugIn;
import nu.zoom.swing.desktop.Workbench;
import nu.zoom.swing.desktop.WorkbenchListener;
import nu.zoom.swing.desktop.WorkbenchMenuBar;
import nu.zoom.swing.desktop.component.filechooser.FileChooserFactory;
import nu.zoom.swing.desktop.component.stringmenu.StringMenu;
import nu.zoom.swing.desktop.component.stringmenu.StringMenuFactory;
import nu.zoom.ui.Resources;
import nu.zoom.ui.Resources.ResourceNotFoundException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * zoom.nu desktop plug-in that handles opening files for tailing. Creates the
 * menu entries and initializes file opener.
 * 
 * @author "Johan Maasing" &lt;johan@zoom.nu&gt;
 * 
 */
public class DesktopPlugIn implements PlugIn, WorkbenchListener {

	static final String RECENT_FILES_MENU_KEY = "svansprogram.recent-files";
	private final Log log = LogFactory.getLog(getClass());
	private final Workbench workbench;
	private final Resources messages;
	private final FileChooserFactory chooserFactory;
	private final StyleRulesPlugIn styleRulesPlugIn;
	private final StringMenuFactory menuFactory;
	private final Preferences preferences;
	private final FileReopener reOpener;
	private final DelayedCursorSwitcher cursorSwitcher;
	private final ErrorReporter errorReporter;
	private final Progress progress;
	private final FontChooserFactory fontChooserFactory;
	private MemStatComponent memStatComponent;
	private FileOpener fileOpener;

	public DesktopPlugIn(final Workbench workbench, final StringMenuFactory menuFactory,
			final FileChooserFactory chooserFactory, final StyleRulesPlugIn styleRulesPlugIn,
			final Preferences preferences, final FileReopener reOpener, final DelayedCursorSwitcher cursorSwitcher,
			final Resources messages, final ErrorReporter errorReporter, final Progress progress,
			final FontChooserFactory fontChooserFactory) {
		super();
		log.trace("Instantiating plugin");
		this.workbench = workbench;
		this.chooserFactory = chooserFactory;
		this.styleRulesPlugIn = styleRulesPlugIn;
		this.menuFactory = menuFactory;
		this.preferences = preferences;
		this.reOpener = reOpener;
		this.cursorSwitcher = cursorSwitcher;
		this.messages = messages;
		this.errorReporter = errorReporter;
		this.progress = progress;
		this.fontChooserFactory = fontChooserFactory;
	}

	@Override
	public void initialize() throws Exception {
		log.trace("Registering as a workbench listener");
		workbench.addWorkBenchListener(this);
	}

	@Override
	public void close() {
		if (this.memStatComponent != null) {
			this.memStatComponent.stop();
		}
	}

	@Override
	public void start() {
		log.trace("Registering plugin on the workbench menu");

		fileOpener =
				new FileOpenerImpl(workbench, messages, preferences, styleRulesPlugIn, reOpener, cursorSwitcher,
						errorReporter, progress, fontChooserFactory);
		OpenFileAction openAction;
		try {
			openAction =
					new OpenFileAction(workbench, messages, chooserFactory, menuFactory, styleRulesPlugIn, fileOpener,
							errorReporter, preferences);

			WorkbenchMenuBar menuBar = workbench.getMenuBar();
			menuBar.addToApplicationMenu(new JMenuItem(openAction));
			StringMenu<File> recentMenu = menuFactory.getMenu(File.class, RECENT_FILES_MENU_KEY);
			recentMenu.addListener(openAction);
			JMenu recentJMenu =
					recentMenu.getJMenu(messages.getMessage("nu.zoom.catonine.recent"), null,
							messages.getMessage("nu.zoom.catonine.recent.forget"),
							messages.getMessage("nu.zoom.catonine.recent.forget.tt"));
			recentJMenu.setMnemonic(KeyEvent.VK_R);
			menuBar.addToApplicationMenu(recentJMenu);

			workbench.registerKeyboardAction(openAction,
					KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK),
					JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

			workbench.getStatusbar().addComponent(Box.createHorizontalGlue());
			memStatComponent =
					new MemStatComponent(messages.getMessage("nu.zoom.catonine.memstat.free"),
							messages.getMessage("nu.zoom.catonine.memstat.total"),
							messages.getMessage("nu.zoom.catonine.memstat.max"));
			memStatComponent.setAlignmentX(Component.RIGHT_ALIGNMENT);
			workbench.getStatusbar().addComponent(memStatComponent);
		} catch (ResourceNotFoundException ex) {
			log.error(ex);
			errorReporter.reportError(ex);
		}
	}

	@Override
	public void visible() {

		EventQueue.invokeLater(new Runnable() {

			@Override
			public void run() {
				reOpenFiles();
			}
		});
	}

	private void reOpenFiles() {
		Set<String> rememeberedFiles = reOpener.getRememeberedFiles();
		for (String filename : rememeberedFiles) {
			log.debug("Reopening file: " + filename);
			File file = new File(filename);
			if (file.canRead()) {
				try {
					fileOpener.openFile(file);
				} catch (ResourceNotFoundException ex) {
					// Log error but don't spam user, this is only preferences
					log.info("Missing configuration", ex);
				}
			} else {
				log.info("Unable to reopen file for reading: " + filename);
				try {
					log.debug("Trying to forget unopenable file : " + filename);
					reOpener.forget(file);
				} catch (IOException e) {
					log.info("Unable to forget unopenable file : " + filename);
				}
			}
		}

	}

}
